//
//  CZNetworkTool.swift
//  czbkiosweibo5
//
//  Created by zhangping on 15/10/13.
//  Copyright © 2015年 zhangping. All rights reserved.
//

import UIKit
import AFNetworking

// MARK: - 请求方法枚举
/// 请求方法枚举
enum CZNetworkMethod: String {
    case GET = "GET"
    case POST = "POST"
}

/*
// domain: 自定义字符串,用于表示错误范围
// code: 错误代码,自定义,表示错误类型,一般是负数开头.通常会将项目中的所有错误都定义在一个文件里面,方便管理
// userInfo: 错误描述
let error = NSError(domain: "cn.itcast.error.net", code: -1, userInfo: ["errorDescription": "token 为空"])
*/
// MARK: - 自定义网络错误
enum CZNetworkError: Int {
    case emptyToken = -1
    case emptyUid = -2
    
    // 枚举可以定义属性
    var errorDescription: String {
        // 根据不同类型,返回不同的值
        switch self {
        case .emptyToken: return "token 为空"
        case .emptyUid: return "uid 为空"
        }
    }
    
    // 枚举可以定义方法
    // 返回根据当前枚举返回错误对象
    func error() -> NSError {
        return NSError(domain: "cn.itcast.error.net", code: rawValue, userInfo: ["errorDescription" : errorDescription])
    }
}

/// 有很多公司会将网络单例继承AFNetworking
class CZNetworkTool: NSObject {
    
    // AFN对象属性
    private var afnManager: AFHTTPSessionManager
    
    // 网络单例
    static let sharedInstance = CZNetworkTool()
    
    override init() {
        // 创建AFN
        let baseUrl = NSURL(string: "https://api.weibo.com/")
        afnManager = AFHTTPSessionManager(baseURL: baseUrl)
        afnManager.responseSerializer.acceptableContentTypes?.insert("text/plain")
    }
    
//    static let sharedInstance: CZNetworkTool = {
//        let baseUrl = NSURL(string: "https://api.weibo.com/")
//        let tool = CZNetworkTool(baseURL: baseUrl)
////        tool.responseSerializer.acceptableContentTypes = NSSet(objects: "application/json", "text/json", "text/javascript", "text/plain")
//// as Set<NSObject>
//        
//        tool.responseSerializer.acceptableContentTypes?.insert("text/plain")
//        return tool
//    }()
    
    // MARK: - 获取AccessToken
    // App Key
    private let client_id = "2356362754"
    
    // App Secret
    private let client_secret = "1d854304b8bbfdeaeb846b8f1399632a"
    
    // 授权回调页
    let redirect_uri = "http://www.baidu.com"

    /**
    获取OauthURL地址
    - returns: OauthURL地址
    */
    func oauthURL() -> NSURL {
        return NSURL(string: "https://api.weibo.com/oauth2/authorize?client_id=\(client_id)&redirect_uri=\(redirect_uri)")!
    }
    
    // MARK: - 定义网络回调的闭包
    typealias NetworkFinishCallback = (result: [String: AnyObject]?, error: NSError?) -> ()
    
    /**
    加载AccessToken
    */
    func loadAccessToken(code: String, finished: NetworkFinishCallback) {
        // url
        let url = "oauth2/access_token"
        
        // 参数
        let parameters = [
            "client_id": client_id,
            "client_secret": client_secret,
            "grant_type": "authorization_code",
            "code": code,
            "redirect_uri": redirect_uri
        ]
        
//        requestPOST(url, parameters: parameters, finished: finished)
        request(CZNetworkMethod.POST, URLString: url, parameters: parameters, finished: finished)
        
        // 调试服务器返回结果
//        responseSerializer = AFHTTPResponseSerializer()
//        afnManager.POST(url, parameters: parameters, success: { (_, result) -> Void in
//            // 服务器返回的数据: expires_in 是整数类型
////            print("result: \(String(data: result as! NSData, encoding: NSUTF8StringEncoding))")
//            finished(result: result as? [String : AnyObject], error: nil)
//            }) { (_, error) -> Void in
//                finished(result: nil, error: error)
//        }
    }
    
    // MARK: - 加载用户信息
    func loadUserInfo(finished: NetworkFinishCallback) {
        // 2/users/show.json
        let url = "2/users/show.json"
        
        // 判断access_token是否为空
//        if CZUserAccount.loadAccount()?.access_token == nil {
//            print("access_token 为空")
//            // access token 为空时, 没有加载用户数据,需要通知调用者
//            // 自定义error
//            
//            // domain: 自定义字符串,用于表示错误范围
//            // code: 错误代码,自定义,表示错误类型,一般是负数开头.通常会将项目中的所有错误都定义在一个文件里面,方便管理
//            // userInfo: 错误描述
////            let error = NSError(domain: "cn.itcast.error.net", code: -1, userInfo: ["errorDescription": "token 为空"])
//            
//            let error = CZNetworkError.emptyToken.error()
//            
//            finished(result: nil, error: error)
//            return
//        }
        
        guard var parameters = tokenDict(finished) else {
            print("没有 token")
            return
        }
        
        // 判断用户UID是否为空
        if CZUserAccount.loadAccount()?.uid == nil {
            print("uid 为空")
            // domain: 自定义字符串,用于表示错误范围
            // code: 错误代码,自定义,表示错误类型,一般是负数开头.通常会将项目中的所有错误都定义在一个文件里面,方便管理
            // userInfo: 错误描述
//            let error = NSError(domain: "cn.itcast.error.net", code: -2, userInfo: ["errorDescription": "token 为空"])
            
            let error = CZNetworkError.emptyUid.error()
            finished(result: nil, error: error)
            return
        }
        
//        let parameters = [
//            "access_token": CZUserAccount.loadAccount()!.access_token!,
//            "uid": CZUserAccount.loadAccount()!.uid!
//        ]
        
        parameters["uid"] = CZUserAccount.loadAccount()!.uid!
        
//        afnManager.GET(url, parameters: parameters, success: { (_, result) -> Void in
//            finished(result: result as? [String : AnyObject], error: nil)
//            }) { (_, error) -> Void in
//                finished(result: nil, error: error)
//        }
        
//        requestGET(url, parameters: parameters, finished: finished)
        request(CZNetworkMethod.GET, URLString: url, parameters: parameters, finished: finished)
    }
    
    // MARK: - 加载微博数据
    /**
    加载微博数据
    - parameter since_id: 加载大于since_id大的微博, 默认为0
    - parameter max_id:   加载小于或等于max_id的微博, 默认为0
    - parameter finished: 回调闭包
    */
    func loadStatus(since_id: Int, max_id: Int, finished: NetworkFinishCallback) {
        // 判断access_token是否为空

        // 守卫,和可选绑定正好相反
        guard var parameters = tokenDict(finished) else {
            // 能到这里面来说明没有值
            return
        }
        
        // 判断是否传入 since_id
        if since_id > 0 {
            // 请求参数添加 since_id
            parameters["since_id"] = since_id
        } else if max_id > 0 {
            // 判断是否传入 max_id
            parameters["max_id"] = max_id - 1
        }
        
        // url地址
        let urlString = "2/statuses/home_timeline.json"
        request(CZNetworkMethod.GET, URLString: urlString, parameters: parameters, finished: finished)
    }
    
    // MARK: - 发送微博
    /**
    发送微博不带图片的微博
    - parameter status:   微博内容
    - parameter image: 微博图片
    - parameter finished: 发送结果
    - 连续两次发布的微博不可以重复,内容不超过140个汉字
    */
    func sendStatus(status: String, image: UIImage?, finished: NetworkFinishCallback) {
        let urlString = "2/statuses/update.json"
        
        guard var parameters = tokenDict(finished) else {
            print("没有token")
            return
        }
        
        parameters["status"] = status
        
        // 判断是否有image
        if let newImage = image {
            // 有图片,发表带图片微博
            sendImageStatus(newImage, urlString: "https://upload.api.weibo.com/2/statuses/upload.json", parameters: parameters, finished: finished)
        } else {
            // 没有图片.发表文本微博
            request(CZNetworkMethod.POST, URLString: urlString, parameters: parameters, finished: finished)
        }
    }
    
    /**
    发布带图片的微博
    - parameter image:      图片
    - parameter urlString:  服务器url地址
    - parameter parameters: 请求参数
    - parameter finished:   发布微博结果回调
    */
    private func sendImageStatus(image: UIImage, urlString: String, parameters: [String: AnyObject], finished: NetworkFinishCallback) {
        afnManager.POST(urlString, parameters: parameters, constructingBodyWithBlock: { (formData) -> Void in
            if let data = UIImagePNGRepresentation(image) {
                
                /*
                    name: api文档中指定的参数名称
                    fileName: 图片保存在服务器上的名称.api上没有指定,可以随便写
                    mimeType: 资源类型
                        格式: 大类/小类
                                image/png
                                image/gif
                                image/jpeg
                */
                formData.appendPartWithFileData(data, name: "pic", fileName: "upload", mimeType: "image/png")
            }
            
            }, success: { (_, result) -> Void in
                finished(result: result as? [String: AnyObject], error: nil)
            }) { (_, error) -> Void in
                finished(result: nil, error: error)
        }
    }
    
    // MARK: - 判断access_token是否为空
    /**
    判断access_token是否为空
    - parameter finished: 网络回调
    - returns: 返回key 为 access_token字典,可能有值,可能没有值
    */
    func tokenDict(finished: NetworkFinishCallback) -> [String: AnyObject]? {
        // 判断access_token是否为空
        if CZUserAccount.loadAccount()?.access_token == nil {
            print("access_token 为空")
            
            let error = CZNetworkError.emptyToken.error()
            
            finished(result: nil, error: error)
            return nil
        }
        
        return ["access_token": CZUserAccount.loadAccount()!.access_token!]
    }
    
    // MARK: - 封装AFN
    // 如果不封装,如果NetrowkTool有50个方法使用到afnManager.GET, 
    // 如果有一天 afnManager.GET 的名称或请求参数发生改变,那需要改动50个地方
    // 当我们将 afnManager.GET 封装后只需要该这一个方法
    // 封装AFN GET方法
    /*private func requestGET(URLString: String, parameters: AnyObject?, finished: NetworkFinishCallback) {
        afnManager.GET(URLString, parameters: parameters, success: { (_, result) -> Void in
            finished(result: result as? [String : AnyObject], error: nil)
            }) { (_, error) -> Void in
                finished(result: nil, error: error)
        }
    }
    
    // 封装AFN POST
    private func requestPOST(URLString: String, parameters: AnyObject?, finished: NetworkFinishCallback) {
        afnManager.POST(URLString, parameters: parameters, success: { (_, result) -> Void in
            finished(result: result as? [String : AnyObject], error: nil)
            }) { (_, error) -> Void in
                finished(result: nil, error: error)
        }
    }*/
    
    // 发现get和post除了方法名称不一样,其他的都一样
    func request(requestMethod: CZNetworkMethod, URLString: String, parameters: AnyObject?, finished: NetworkFinishCallback) {
        
        // 定义成功时的回调
        let successCallback = { (_: NSURLSessionDataTask, result: AnyObject) -> Void in
            finished(result: result as? [String : AnyObject], error: nil)
        }
        
        // 定义失败时的回调
        let failureCallback = { (_: NSURLSessionDataTask, error: NSError) -> Void in
            finished(result: nil, error: error)
        }
        
        // 判断是get还是post
        switch requestMethod {
        case .GET:
            afnManager.GET(URLString, parameters: parameters, success: successCallback, failure: failureCallback)
        case .POST:
            afnManager.POST(URLString, parameters: parameters, success: successCallback, failure: failureCallback)
        }
    }
}
